using System;
using HyperActive.Core;
using HyperActive.Dominator;
using HyperActive.SchemaProber;
using HyperActive.Core.Generators;
using System.CodeDom;

namespace SimplePMT.Components.ActiveRecordExtensions
{
	public class ValidationActiveRecordGenerator : LazyActiveRecordGenerator
	{		
		/// <summary>
		/// Initializes a new instance of the ValidationActiveRecordGenerator class.
		/// </summary>
		public ValidationActiveRecordGenerator()
		{
		}
		protected override ClassDeclaration CreateClass(NamespaceDeclaration namespaceDeclaration, TableSchema table)
		{
			return namespaceDeclaration.AddClass(this.NameProvider.GetClassName(table), true)
				.InheritsFrom("Castle.ActiveRecord.ActiveRecordValidationBase", this.NameProvider.GetClassName(table));
		}
		protected override PropertyDeclaration CreatePrimaryKeyProperty(ClassDeclaration cdecl, TableSchema table)
		{
			PropertyDeclaration pk = base.CreatePrimaryKeyProperty(cdecl, table);
			pk.AddComment("This is the primary key and maps to {0}", table.PrimaryKey.Name);
			return pk;
		}

		protected override void CreateNonKeyProperty(ClassDeclaration classDeclaration, ColumnSchema column)
		{
			string propertyName = this.NameProvider.GetPropertyName(column);
			string fieldName = this.NameProvider.GetFieldName(column);
			PropertyDeclaration prop = classDeclaration.AddProperty(propertyName, fieldName, column.DataType, column.Nullable);

			prop.AddComment("Gets or sets the {0} of the {1}.", this.NameProvider.GetPropertyName(column), classDeclaration.Name);
			if (column.Nullable)
				prop.AddComment("This property is nullable.");
			else
				prop.AddComment("This property cannot be null.");
			if (column.DataType == typeof(string))
				prop.AddComment("The max length of this property is {0}.", column.Length);

			AttributeDeclaration propAttrib = prop.AddAttribute("Castle.ActiveRecord.PropertyAttribute")
					.AddQuotedArgument(column.Name)
					.AddArgument("Length=" + (column.Length < 0 ? 0 : column.Length).ToString())
					.AddArgument("NotNull=" + (column.Nullable == false).ToString().ToLower());

			if (column.SqlType == System.Data.SqlDbType.Image)
				propAttrib.AddArgument("ColumnType=\"BinaryBlob\"");

			if (column.SqlType == System.Data.SqlDbType.Xml)
				propAttrib.AddArgument("ColumnType=\"StringClob\"");

			//if (column.IsComputed)
			//	propAttrib.AddArgument("Formula=\"" + Trim(column.Formula) + "\"");

			AttributeDeclaration validator = null;
			switch (column.DataType.FullName)
			{
				case "System.String":
					if (column.Nullable)
					{
						validator = prop.AddAttribute("Gals.ActiveRecordExtensions.ValidateNullOrMaxAttribute");
						validator.AddArgument(column.Length.ToString()).AddQuotedArgument(String.Format("{0} must be null or a max length of {1}", column.Name, column.Length));
					}
					else
					{
						validator = prop.AddAttribute("Castle.Components.Validator.ValidateLengthAttribute");
						validator.AddArgument("1").AddArgument(column.Length.ToString()).AddQuotedArgument(String.Format("{0} must be value containing 1 to {1} characters", column.Name, column.Length));
					}
					break;
			}
		}

		private string Trim(string s)
		{
			string result = s.Replace("[", "").Replace("]", "").TrimStart("(".ToCharArray());
			return result.Replace("))", ")");
		}

		protected override ClassDeclaration CreateConstructors(ClassDeclaration classDecl, TableSchema table)
		{
			string summary = String.Format("Initializes a new instance of {0}.", classDecl.Name);
			classDecl.AddConstructor(summary);
			PrimaryKeyColumnSchema pk = table.PrimaryKey;
			if (pk != null)
			{
				string name = pk.Name.Replace(pk.Table.Name, "");
				if (name.Length == 2)
					name = name.ToLower();
				classDecl.AddConstructor(summary, new ConstructorArg(pk.DataType, this.NameProvider.GetArgumentName(name), this.NameProvider.GetFieldName(name),
					String.Format("The {0} of the {1}", this.NameProvider.GetArgumentName(name), classDecl.Name)));

				MethodDeclaration method = classDecl.AddMethod("Find", new CodeDomTypeReference(this.NameProvider.GetClassName(table)));
				method.MethodAttributes.Add(MemberAttributes.Public | MemberAttributes.Static | MemberAttributes.Final);
				method.AddParameter(typeof(int), "id");
				method.Returns("FindByPrimaryKey").With("id", "false");
				
			}
			return classDecl;
		}
		//public override ClassDeclaration AddMethods(ClassDeclaration classDecl, TableSchema table)
		//{
		//	MethodDeclaration method = classDecl.AddMethod("Find", new CodeDomTypeReference(this.NameProvider.GetClassName(table)));
		//	method.MethodAttributes.Add(MemberAttributes.Static | MemberAttributes.Public | MemberAttributes.Final);
		//	method.AddParameter(typeof(int), "id");
		//	return classDecl;
		//}
	}
}
